package main

import (
	"fmt"
)

const (
	SOCKS5_VERSION = 0x05

	SOCKS5_CMD_CONNECT = 0x01
	SOCKS5_CMD_BIND    = 0x02
	SOCKS5_CMD_UDP     = 0x03

	SOCKS5_ADDR_TYPE_IPV4       = 0x01
	SOCKS5_ADDR_TYPE_IPV6       = 0x04
	SOCKS5_ADDR_TYPE_DOMAINNAME = 0x03

	SOCKS5_REP_SUCCESS               = 0x00
	SOCKS5_REP_SERVER_FAILURE        = 0x01
	SOCKS5_REP_NOT_ALLOWED           = 0x02
	SOCKS5_REP_NETWORK_UNREACHABLE   = 0x03
	SOCKS5_REP_HOST_UNREACHABLE      = 0x04
	SOCKS5_REP_CONNECTION_REJECT     = 0x05
	SOCKS5_REP_TTL_EXPIRED           = 0x06
	SOCKS5_REP_COMMAND_NOT_SUPPORTED = 0x07
	SOCKS5_REP_ADDRESS_NOT_SUPPORTED = 0x08
)

// 握手包
type HandshakePacket struct {
	// 版本
	Ver byte
	// 支持认证方法的大小
	NMethods byte
	// 支持的认证方法，每一种方法占一个字节
	Methods []byte

	Err error
}

type EchoHandshakePacket struct {
	// 版本
	Ver byte
	// 支持的认证方法
	Method byte
}

func (e EchoHandshakePacket) bytes() []byte {
	return []byte{e.Ver, e.Method}
}

// 请求包
type RequestPacket struct {
	// 版本
	Ver byte
	// 命令类型
	Cmd byte
	// 保留 0x00
	Rsv byte
	// 地址类型
	Atyp byte
	// 目的地址
	DstAddr []byte
	// 目的端口
	DstPort uint16

	Err error
}

func (r RequestPacket) ReqAddr() string {
	if r.Atyp == SOCKS5_ADDR_TYPE_IPV4 {
		return fmt.Sprintf("%d.%d.%d.%d", r.DstAddr[0], r.DstAddr[1], r.DstAddr[2], r.DstAddr[3])
	} else if r.Atyp == SOCKS5_ADDR_TYPE_IPV6 {
		return fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
			r.DstAddr[0], r.DstAddr[1], r.DstAddr[2], r.DstAddr[3], r.DstAddr[4],
			r.DstAddr[5], r.DstAddr[6], r.DstAddr[7], r.DstAddr[8], r.DstAddr[9],
			r.DstAddr[10], r.DstAddr[11], r.DstAddr[12], r.DstAddr[13], r.DstAddr[14],
			r.DstAddr[15])
	} else if r.Atyp == SOCKS5_ADDR_TYPE_DOMAINNAME {
		return string(r.DstAddr)
	}
	return ""
}

func (r RequestPacket) AddrAndPortString() string {
	var s string = ""
	if r.Atyp == SOCKS5_ADDR_TYPE_IPV4 {
		s = fmt.Sprintf("%d.%d.%d.%d:%d", r.DstAddr[0], r.DstAddr[1], r.DstAddr[2], r.DstAddr[3], r.DstPort)
	} else if r.Atyp == SOCKS5_ADDR_TYPE_IPV6 {
		s = fmt.Sprintf("%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%d",
			r.DstAddr[0], r.DstAddr[1], r.DstAddr[2], r.DstAddr[3], r.DstAddr[4],
			r.DstAddr[5], r.DstAddr[6], r.DstAddr[7], r.DstAddr[8], r.DstAddr[9],
			r.DstAddr[10], r.DstAddr[11], r.DstAddr[12], r.DstAddr[13], r.DstAddr[14],
			r.DstAddr[15], r.DstPort)
	} else if r.Atyp == SOCKS5_ADDR_TYPE_DOMAINNAME {
		s = fmt.Sprintf("%s:%d", string(r.DstAddr), r.DstPort)
	}

	return s
}

func (r RequestPacket) ReqDesc() string {
	var desc string = "->"
	desc = desc + fmt.Sprintf("%s:%d", r.ReqAddr(), r.DstPort)
	return desc
}

// 请求回复包
type ReplyPacket struct {
	// 版本
	Ver byte
	// 返回结果
	Rep byte
	// 保留 0x00
	Rsv byte
	// 地址类型
	Atyp byte
	// 服务器绑定的地址
	BindAddr []byte
	// 服务器绑定的端口
	BindPort uint16
}

func (r ReplyPacket) bytes() []byte {
	return []byte{r.Ver, r.Rep, 0x00, r.Atyp, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}
